#ifndef __MY_ROOM_H__
#define __MY_ROOM_H__
#include "OnlineManager.hpp"
#include "Database.hpp"
#include <vector>
#include "Util.hpp"

// 游戏房间
class Room
{
private:
    // 房间状态
    enum RoomStatus
    {
        NEW_CREATE,
        GAME_GOING,
        GAME_OVER
    };
    // 棋盘单格状态
    enum BoardPattern
    {
        SPACE = 0,
        WHITE = 1,
        BLACK = 2
    };

    BoardPattern CheckWin(int row, int col)
    {
        auto CheckLine = [row, col, this](int row_off, int col_off)
        {
            int count = 1;
            int cur_r = row + row_off, cur_c = col + col_off;
            while (0 <= cur_r && cur_r < row_num && 0 <= cur_c && cur_c < col_num && _board[cur_r][cur_c] == _board[row][col])
            {
                count++;
                cur_r += row_off;
                cur_c += col_off;
            }
            cur_r = row - row_off, cur_c = col - col_off;
            while (0 <= cur_r && cur_r < row_num && 0 <= cur_c && cur_c < col_num && _board[cur_r][cur_c] == _board[row][col])
            {
                count++;
                cur_r -= row_off;
                cur_c -= col_off;
            }
            return count >= 5;
        };

        if (_board[row][col] != SPACE && CheckLine(1, 0) || CheckLine(0, 1) || CheckLine(1, 1) || CheckLine(1, -1))
            return _board[row][col];
        else
            return SPACE;
    }

public:
    Room(id_t id, Table_user *tb, OnlineManager *online_manager)
        : _id(id), _tb(tb), _online_manager(online_manager), _player(3, 0), _board(row_num, std::vector<BoardPattern>(col_num, SPACE))
    {
        LOG(LogLevel::INFO) << "房间[id=" << _id << "]创建成功!";
    }
    id_t Id() { return _id; }
    RoomStatus Status() { return _status; }
    id_t PlayerCount() { return _player_count; }
    // 白棋加入
    bool AddWhitePlayer(id_t id)
    {
        if (_player[WHITE] > 0 || _player_count > 1)
            return false;
        _player_count++;
        _player[WHITE] = id;
        // LOG(LogLevel::DEBUG) << "_player[WHITE]: " << id;
        if(_player_count == 2)
            _status = GAME_GOING;
        return true;
    }
    // 黑棋加入
    bool AddBlackPlayer(id_t id)
    {
        if (_player[BLACK] > 0 || _player_count > 1)
            return false;
        _player_count++;
        _player[BLACK] = id;
        // LOG(LogLevel::DEBUG) << "_player[BLACK]: " << id;
        if(_player_count == 2)
            _status = GAME_GOING;
        return true;
    }
    id_t WhitePlayer() { return _player[WHITE]; }
    id_t BlackPlayer() { return _player[BLACK]; }

    // 处理落子请求
    Json::Value Chess(const Json::Value &req)
    {
        Json::Value resq = req;
        // 检查下棋位置
        id_t row = req["row"].asUInt();
        id_t col = req["col"].asUInt();
        if (_board[row][col] != SPACE)
        {
            resq["result"] = false;
            resq["reason"] = "此处已有棋子!";
            return resq;
        }

        // 下棋
        id_t uid = req["uid"].asUInt();
        BoardPattern cur = (uid == _player[WHITE] ? WHITE : BLACK);
        _board[row][col] = cur;

        // 检查是否胜出
        BoardPattern winner = CheckWin(row, col);
        if (winner != SPACE)
        {
            resq["winner"] = _player[winner]; 
            resq["reason"] = "胜出!";
        }
        resq["result"] = true;
        return resq;
    }

    // 处理聊天请求
    Json::Value Chat(const Json::Value &req)
    {
        Json::Value resq = req;
        // 检查是否存在敏感词
        static std::vector<std::string> sensitive = {"垃圾", "废物"};
        std::string msg = req["message"].asString();
        for (auto &word : sensitive)
        {
            if (msg.find(word) != std::string::npos)
            {
                resq["result"] = false;
                resq["reason"] = "发送失败，消息包含敏感词!";
                return resq;
            }
        }

        resq["result"] = true;
        return resq;
    }

    // 处理退出请求
    Json::Value Exit(const id_t uid)
    {
        Json::Value resq;
        resq["op_type"] = "chess";
        BoardPattern cur = (uid == _player[WHITE] ? WHITE : BLACK);
        BoardPattern other = (cur != WHITE ? WHITE : BLACK);
        _player_count--;
        if (_status == GAME_GOING)
        {
            resq["result"] = true;
            resq["reason"] = "对方已掉线...";
            resq["winner"] = _player[other];
            resq["row"] = -1;
            resq["col"] = -1;
        }
        return resq;
    }

    // 处理请求
    void RequestHandler(const Json::Value &req)
    {
        Json::Value resq = req;
        // 检查房间状态
        if (_status != GAME_GOING)
        {
            resq["result"] = false;
            switch (_status)
            {
            case NEW_CREATE:
                resq["reason"] = "对局还未开始!";
                break;
            case GAME_OVER:
                resq["reason"] = "对局已结束!";
                break;
            }
            return Broadcast(resq);
        }

        // 检查请求房间号与当前房间号是否匹配
        if (req["room_id"].asUInt() != _id)
        {
            resq["result"] = false;
            resq["reason"] = "房间号不匹配!";
            return Broadcast(resq);
        }

        std::string op_type = req["op_type"].asString();
        if (op_type == "chess")
        {
            resq = Chess(req);
        }
        else if (op_type == "chat")
        {
            resq = Chat(req);
        }
        else if (op_type == "exit")
        {
            id_t uid = req["uid"].asUInt();
            resq = Exit(uid);
        }
        else
        {
            // 未知操作类型，什么也不做
            return;
        }
        ResqResponser(resq);
    }

    void ResqResponser(Json::Value& resq)
    {
        // 判断是否有胜者
        if (!resq["winner"].isNull())
        {
            id_t winner = resq["winner"].asUInt();
            id_t other = (winner != _player[WHITE] ? _player[WHITE] : _player[BLACK]);
            _tb->CountWin(winner);
            _tb->CountLose(other);
            _status = GAME_OVER;
        }
        else
            resq["winner"] = 0;
        return Broadcast(resq);
    }

    void Broadcast(const Json::Value &resq)
    {
        // 将消息序列化
        std::string body;
        Util_Json::serialize(resq, body);

        // 获取用户连接并发送消息
        wsserver_t::connection_ptr wconn = _online_manager->GetConFromRoom(_player[WHITE]);
        if (wconn.get() != nullptr)
        {
            wconn->send(body);
        }
        wsserver_t::connection_ptr bconn = _online_manager->GetConFromRoom(_player[BLACK]);
        if (bconn.get() != nullptr)
        {
            bconn->send(body);
        }
    }

    ~Room()
    {
        LOG(LogLevel::INFO) << "房间[id=" << _id << "]即将销毁!";
    }

private:
    id_t _id;                                  // 房间id
    RoomStatus _status = NEW_CREATE;               // 房间状态
    id_t _player_count = 0;                    // 房间中的用户数量
    std::vector<id_t> _player;                 // 1:白棋用户id - 2:黑棋用户id
    Table_user *_tb = nullptr;                     // 用户表
    OnlineManager *_online_manager = nullptr;      // 在线用户管理
    std::vector<std::vector<BoardPattern>> _board; // 棋盘
    static const id_t row_num = 15;
    static const id_t col_num = 15;
};

using RoomPtr = std::shared_ptr<Room>;

class RoomManager
{
public:
    RoomManager(Table_user *tb, OnlineManager *online_manager)
        : _tb(tb), _online_manager(online_manager)
    {
        LOG(LogLevel::INFO) << "房间管理器创建成功!";
    }
    // 两个玩家匹配成功，创建房间并返回房间指针
    RoomPtr CreateRoom(id_t uid1, id_t uid2)
    {
        // 判断玩家是否掉线
        if(!_online_manager->IsInGameHall(uid1))
        {
            LOG(LogLevel::ERROR) << "玩家id[" << uid1 << "]已掉线, 创建房间失败!";
            return RoomPtr();
        }
        if(!_online_manager->IsInGameHall(uid2))
        {
            LOG(LogLevel::ERROR) << "玩家id[" << uid2 << "]已掉线, 创建房间失败!";
            return RoomPtr();
        }

        // 创建房间
        std::unique_lock<std::mutex> lockguard(_mtx);
        RoomPtr new_room(new Room(_next_rid++, _tb, _online_manager));
        new_room->AddWhitePlayer(uid1);
        // LOG(LogLevel::DEBUG) << "white: " << uid1;
        new_room->AddBlackPlayer(uid2);
        // LOG(LogLevel::DEBUG) << "black: " << uid2;

        // 保存房间
        _rid_room[new_room->Id()] = new_room;
        _uid_rid[uid1] = new_room->Id();
        _uid_rid[uid2] = new_room->Id();

        return new_room;
    }
    // 通过uid查找房间
    RoomPtr GetRoomByUid(id_t uid)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        auto it1 = _uid_rid.find(uid);
        if(it1 == _uid_rid.end())
        {
            return RoomPtr();
        }
        auto it2 = _rid_room.find(it1->second);
        if(it2 == _rid_room.end())
        {
            return RoomPtr();
        }
        return it2->second;
    }
    // 通过rid查找房间
    RoomPtr GetRoomByRid(id_t rid)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        auto it = _rid_room.find(rid);
        if(it == _rid_room.end())
        {
            return RoomPtr();
        }
        return it->second;
    }
    // 销毁房间
    void DestroyRoom(id_t rid)
    {
        // 获取房间
        RoomPtr room = GetRoomByRid(rid);
        if(room.get() == nullptr)
        {
            return;
        }

        // 删除房间
        _rid_room.erase(rid);

        // 删除用户信息
        _uid_rid.erase(room->WhitePlayer());
        _uid_rid.erase(room->BlackPlayer());
    }
    // 将用户移出房间
    void RemoveUser(id_t uid)
    {
        RoomPtr room = GetRoomByUid(uid);
        if(room.get() == nullptr)
        {
            return;
        }

        Json::Value resq = room->Exit(uid);
        if(room->PlayerCount() == 0)
            DestroyRoom(room->Id());
        room->ResqResponser(resq);
    }
    ~RoomManager()
    {
        LOG(LogLevel::INFO) << "房间管理器即将销毁!";
    }
private:
    id_t _next_rid = 0; // 下一个待分配的房间id
    std::mutex _mtx;
    Table_user *_tb;
    OnlineManager *_online_manager;
    std::unordered_map<id_t, RoomPtr> _rid_room; // 房间id - 房间指针
    std::unordered_map<id_t, id_t> _uid_rid; // 用户id - 房间id
};

#endif